package com.ruoyi.common.utils;

import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 二维码 条形码生成
 */
public class CodeGeneratorUtil {

    private static final int BLACK = 0xFF000000;
    private static final int WHITE = 0xFFFFFFFF;

    /**
     * 生成QR码
     *
     * @param data     要存储在QR码中的数据，可以是文本、URL等
     * @param width    QR码的宽度（像素）
     * @param height   QR码的高度（像素）
     * @param filePath 生成的QR码文件的保存路径
     */
    public static String generateQrCode(String data, int width, int height, String filePath) {

        String fileName = UUID.randomUUID().toString();
        String filePaths = filePath + File.separator + fileName + ".png";

        try {
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置字符编码
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 错误纠正级别
            hints.put(EncodeHintType.MARGIN, 1); // 二维码边距

            MultiFormatWriter writer = new MultiFormatWriter();
            BitMatrix bitMatrix = writer.encode(data, BarcodeFormat.QR_CODE, width, height, hints);

            // 创建BufferedImage对象来表示QR码
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
                }
            }

            // 检查目录是否存在，若不存在则创建
            File directory  = new File(filePath);
            if (!directory .exists()) {
                directory .mkdirs();
            }

            // 将QR码保存到文件
            File qrCodeFile = new File(filePaths);
            ImageIO.write(image, "png", qrCodeFile);
        } catch (Exception e) {
        }
        return File.separator + fileName + ".png";
    }

    /**
     * 二维码生成
     * @param url： url地址
     * @param path：二维码存储路径
     * @return： 二维码地址
     */
    public static String createQrCode(String url, String path) {
        String fileName = UUID.randomUUID().toString();
        String filePaths = fileName + ".png";
        try {
            Map<EncodeHintType, String> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 400, 400, hints);
            File file = new File(path, filePaths);
            if (file.exists() || ((file.getParentFile().exists() || file.getParentFile().mkdirs()) && file.createNewFile())) {
                writeToFile(bitMatrix, "jpg", file);
//                return file.toString();
                return "/"+filePaths;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("无法将格式为"+ format +"的图像写入"+ file);
        }
    }

    private static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    /**
     * 生成条形码
     *
     * @param data     要存储在条形码中的数据，可以是商品条形码等
     * @param width    条形码的宽度（像素）
     * @param height   条形码的高度（像素）
     * @param directoryPath 生成的条形码文件的保存路径
     */
    public static String generateBarCode(String data, int width, int height, String directoryPath) {
        String fileName = UUID.randomUUID().toString();
        String filePaths = directoryPath + File.separator + fileName + ".png";
        try {
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置字符编码

            MultiFormatWriter writer = new MultiFormatWriter();
            BitMatrix bitMatrix = writer.encode(data, BarcodeFormat.CODE_128, width, height, hints);

            // 创建BufferedImage对象来表示条形码
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0 : 0xFFFFFF); // 生成黑色条和白色背景的条形码
                }
            }

            // 检查目录是否存在，若不存在则创建
            File directory  = new File(directoryPath);
            if (!directory .exists()) {
                directory .mkdirs();
            }

            // 创建条形码文件
            File barcodeFile = new File(filePaths);
            // 将条形码写入
            ImageIO.write(image, "png", barcodeFile);
        } catch (Exception e) {
            filePaths = null;
        }
        return File.separator + fileName + ".png";
    }

    /**
     * 生成用户二维码
     * @param content 二维码信息
     * @param width 图片宽
     * @param height 图片高
     * @param response
     */
    public static void generateQrcode(String content, int width, int height, HttpServletResponse response) {
        try {
            QrConfig qrConfig = new QrConfig(width, height);
            QrCodeUtil.generate(content, qrConfig, "png", response.getOutputStream());
            System.out.println("生成二维码成功!");
        } catch (IOException e) {
            System.out.println("发生错误！ {}！"+ e.getMessage());
        }
    }

}
